/**
 *
 */
package jp.seraph.jsade.math;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 多項式を表すクラス<br>
 * <br>
 * 多項式は項（term）の集まりとしてあらわされている。<br>
 * 項は係数と指数によって表わされている。
 * 
 */
public class PolynomialFunction implements Iterable<PolynomialFunction.TermEntry> {
    /**
     * 奇数番目引数を係数部 偶数番目引数を指数部として、このインスタンスを生成するコンストラクタ
     * 
     * @param aParameters
     */
    public PolynomialFunction(double... aParameters) {
        int tLength = aParameters.length;
        if (tLength % 2 != 0)
            throw new IllegalArgumentException("このコンストラクタに渡すパラメータ数は偶数でなければなりません");

        int tCount = tLength / 2;
        TermEntry[] tEntries = new TermEntry[tCount];
        for (int i = 0; i < tCount; i++) {
            tEntries[i] = new TermEntry(aParameters[2 * i], aParameters[2 * i + 1]);
        }

        this.init(tEntries);
    }

    /**
     * 項が0個の多項式を生成する。
     */
    public PolynomialFunction() {
        this(new TermEntry[0]);
    }

    /**
     * 引数に与えられた項からなるこのクラスのインスタンスを生成するコンストラクタ。
     * 
     * @param aEntries
     */
    public PolynomialFunction(TermEntry... aEntries) {
        this.init(aEntries);
    }

    private void init(TermEntry... aEntries) {
        mEntries = new ArrayList<TermEntry>();
        for (TermEntry tEntry : aEntries) {
            mEntries.add(tEntry);
        }
    }

    private List<TermEntry> mEntries;

    /**
     * 項を追加する。
     * 
     * @param aEntry
     */
    public void addEntry(TermEntry aEntry) {
        mEntries.add(aEntry);
    }

    /**
     * 項を追加する。
     * 
     * @param aCoefficient
     *            追加する項の係数
     * @param aExponent
     *            追加する項の指数
     */
    public void addEntry(double aCoefficient, double aExponent) {
        this.addEntry(new TermEntry(aCoefficient, aExponent));
    }

    /**
     * この多項式を、与えられた引数で計算して返す。
     * 
     * @param aArgument
     *            引数
     * @return 計算結果
     */
    public double eval(double aArgument) {
        double tResult = 0;
        for (TermEntry tEntory : mEntries) {
            tResult += tEntory.getCoefficient() * Math.pow(aArgument, tEntory.getExponent());
        }

        return tResult;
    }

    /**
     * この多項式が保持する項を返す。
     * 
     * @return
     */
    public TermEntry[] getEntries() {
        return mEntries.toArray(new TermEntry[0]);
    }

    /**
     * 
     * @see java.lang.Iterable#iterator()
     */

    public Iterator<TermEntry> iterator() {
        return mEntries.iterator();
    }

    /**
     * 項の係数部と指数部を表すクラス
     * 
     * 
     */
    public static class TermEntry {
        public TermEntry(double aCoefficient, double aExponent) {
            mCoefficient = aCoefficient;
            mExponent = aExponent;
        }

        private double mCoefficient;

        private double mExponent;

        /**
         * 係数部を返す
         * 
         * @return 係数
         */
        public double getCoefficient() {
            return mCoefficient;
        }

        /**
         * 指数部を返す
         * 
         * @return 指数
         */
        public double getExponent() {
            return mExponent;
        }
    }
}
